/******************************************************************************\
    Object.hpp contains classes for all self-destructing objects.
    Copyright (C) 2008  Victor Vinogradov (fly3333@gmail.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
\******************************************************************************/

#ifndef __OBJECT_HPP
#define __OBJECT_HPP

#include <windows.h>
#include <crtdbg.h>

/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif
#endif

class cSubObject
{
private:
	long UsersCount;

	void Attach()
	{
		InterlockedIncrement( &UsersCount );
	}
	void Detach()
	{
		if( InterlockedDecrement( &UsersCount ) == 0 )
			delete this;
	}

protected:
	cSubObject()
		: UsersCount( 0 )
	{
	}
	virtual ~cSubObject()
	{
	}

	template< class cSubObjectType >
	friend class cObject;
};

//template< class cWardObject >
//class cSubPointerObject : public cSubObject
//{
//	cWardObject *WardObject;
//public:
//	cSubPointerObject( cWardObject *ward_object )
//		: WardObject( ward_object )
//	{
//	}
//	~cSubPointerObject()
//	{
//		delete WardObject;
//	}
//	cWardObject *Pointer() const
//	{
//		return WardObject;
//	}
//};

template< class cSubObjectType >
class cObject
{
private:
	cSubObjectType *SubObject;

protected:
	void SwitchToSubObject( cSubObjectType *sub_object )
	{
		if( SubObject != NULL )
			SubObject->Detach();
		SubObject = sub_object;
		if( SubObject != NULL )
			SubObject->Attach();
	}
	cSubObjectType *GetSubObject() const
	{
		return SubObject;
	}

public:
	cObject()
		: SubObject( NULL )
	{
	}
	cObject( const cObject &object )
		: SubObject( object.SubObject )
	{
		if( SubObject != NULL )
			SubObject->Attach();
	}
	virtual ~cObject()
	{
		if( SubObject != NULL )
			SubObject->Detach();
	}
	cObject &operator =( const cObject &object )
	{
		if( SubObject != NULL )
			SubObject->Detach();
		SubObject = object.SubObject;
		if( SubObject != NULL )
			SubObject->Attach();
		return *this;
	}
};

//template< class cWardObjectType >
//class cPointerObject : public cObject< cSubPointerObject< cWardObjectType > >
//{
//protected:
//	bool SwitchToWardObject( cWardObjectType *ward_object )
//	{
//		cSubPointerObject< cWardObjectType > *sub_object;
//		try
//		{
//			sub_object = new cSubPointerObject< cWardObjectType >( ward_object );
//		}
//		catch( ... )
//		{
//			return false;
//		}
//		SwitchToSubObject( sub_object );
//		return true;
//	}
//public:
//	cWardObjectType &operator *() const
//	{
//		_ASSERT( GetSubObject() != NULL );
//		return *GetSubObject()->Pointer();
//	}
//	cWardObjectType *operator ->() const
//	{
//		_ASSERT( GetSubObject() != NULL );
//		return GetSubObject()->Pointer();
//	}
//};

#endif
